package com.microframework.boot.system.controller;

import java.sql.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Page;
import com.microframework.base.core.datasource.annotation.Tx;
import com.microframework.base.core.util.SecurityUtils;
import com.microframework.base.core.util.UuidUtil;
import com.microframework.base.web.page.PageQuery;
import com.microframework.base.web.resp.R;
import com.microframework.boot.system.model.domain.Role;
import com.microframework.boot.system.model.domain.RoleMenu;
import com.microframework.boot.system.service.IRoleService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.constraints.NotBlank;
import lombok.extern.slf4j.Slf4j;

/**
 * 角色管理控制器
 */
@Slf4j
@RestController
@RequestMapping("/sys/role")
@Tag(name = "角色管理", description = "角色管理相关接口")
public class RoleController {

    @Autowired
    private IRoleService roleService;
    
    @PostMapping("/pages")
    @Operation(summary = "分页查询角色列表", description = "分页查询角色数据")
    public R<Page<Role>> pages(@RequestBody PageQuery<Role> pageQuery) {
        return R.ok(roleService.pages(pageQuery));
    }
    
	@Operation(summary = "保存角色")
	@Parameters({ @Parameter(name = "role", description = "角色", required = true) })
	@PostMapping("/save")
	public R<Role> save(HttpServletRequest request, @RequestBody Role role) {
		try {
			if (StrKit.notBlank(role.getId())) {
				Role checkRole=Role.dao.findFirst("select id from "+Role.TABLE_NAME+" where code=? and id!=?",role.getCode(),role.getId());
				if(checkRole!=null) {
					return R.fail("角色标识重复.");
				}
				role.setModifyTime(new Date(System.currentTimeMillis()));
				role.setModifyUserId(SecurityUtils.getUserId());
				if (role.update()) {
					return R.ok(role);
				} else {
					return R.fail("更新失败.");
				}
			} else {
				Role checkRole=Role.dao.findFirst("select id from "+Role.TABLE_NAME+" where code=? ",role.getCode());
				if(checkRole!=null) {
					return R.fail("角色标识重复.");
				}
				role.setId(UuidUtil.getUUID());
				role.setCreateTime(new Date(System.currentTimeMillis()));
				role.setCreateUserId(SecurityUtils.getUserId());
				if (role.save()) {
					return R.ok(role);
				} else {
					return R.fail("保存失败.");
				}
			}
		} catch (Exception e) {
			return R.fail(e.getMessage());
		}
	}
	
	@Operation(summary = "删除角色")
	@Parameters({ @Parameter(name = "id", description = "角色id", required = true) })
	@DeleteMapping("/detain/{id}")
	public R<String> deleteById(@PathVariable("id") String id) {
		try {
			Role role=new Role();
			role.setId(id);
			role.setIsDel("1");
			if(role.update()) {
				return R.ok("删除角色成功.");
			}else {
				return R.fail("删除角色失败.");
			}
		}catch (Exception e) {
			log.error("删除角色异常:{}",e.getMessage());
			return R.fail(e.getMessage());
		}
	}
	
	@Operation(summary = "获取角色拥有菜单ID集合")
	@Parameters({ @Parameter(name = "id", description = "角色ID", required = true) })
	@GetMapping("/{id}/menus")
	public R<List<String>> getRoleMenuIdsById(@PathVariable("id") String id) {
	    try {
	        List<String> roleMenuIds = RoleMenu.dao.find(
	                "SELECT menu_id FROM " + RoleMenu.TABLE_NAME + " WHERE role_id = ? ", 
	                id
	            ).stream()
	            .map(RoleMenu::getMenuId)
	            .collect(Collectors.toList());
	        return R.ok(roleMenuIds);
	    } catch (Exception e) {
	        log.error("获取角色[{}]菜单ID集合异常: {}", id, ExceptionUtils.getStackTrace(e));
	        return R.fail("获取菜单信息失败，请稍后重试");
	    }
	}
	
	@Operation(summary = "保存角色拥有菜单")
	@Parameters({
	    @Parameter(name = "id", description = "角色ID", required = true),
	    @Parameter(name = "menuIds", description = "菜单ID集合", required = false)
	})
	@PostMapping("/{id}/store/menus")
	@Tx
	public R<Void> saveRoleMenuIds(
	        @PathVariable("id") @NotBlank(message = "角色ID不能为空") String id,
	        @RequestBody List<String> menuIds) {
	    
	    try {
	        // 1. 参数校验放在方法开头
	        if (menuIds==null || menuIds.isEmpty()) {
	            // 清空角色所有菜单
	            int delCount = Db.delete("DELETE FROM " + RoleMenu.TABLE_NAME + " WHERE role_id = ?", id);
	            log.info("角色[{}]菜单已清空，删除{}条记录", id, delCount);
	            return R.ok("已取消所有菜单授权");
	        }

	        // 2. 获取现有菜单ID集合 (使用Set提高查询效率)
	        Set<String> existingMenuIds = RoleMenu.dao.find(
	                "SELECT menu_id FROM " + RoleMenu.TABLE_NAME + " WHERE role_id = ?", id)
	            .stream()
	            .map(RoleMenu::getMenuId)
	            .collect(Collectors.toSet());

	        // 3. 计算需要删除和需要新增的菜单ID
	        Set<String> newMenuIds = new HashSet<>(menuIds);
	        
	        // 需要删除的菜单ID（存在但不在新列表中）
	        List<String> idsToDelete = existingMenuIds.stream()
	            .filter(menuId -> !newMenuIds.contains(menuId))
	            .collect(Collectors.toList());
	        
	        // 需要新增的菜单ID（新列表中但不存在）
	        List<String> idsToAdd = newMenuIds.stream()
	            .filter(menuId -> !existingMenuIds.contains(menuId))
	            .collect(Collectors.toList());

	        // 4. 批量删除操作
	        if (!idsToDelete.isEmpty()) {
	            // 分批次处理（每批最多1000个）
	            int batchSize = 1000;
	            for (int i = 0; i < idsToDelete.size(); i += batchSize) {
	                int end = Math.min(i + batchSize, idsToDelete.size());
	                List<String> batch = idsToDelete.subList(i, end);
	                
	                // 生成占位符字符串（如 ?,?,?）
	                String placeholders = batch.stream()
	                    .map(item -> "?")
	                    .collect(Collectors.joining(","));
	                
	                // 构建参数数组：角色ID + 菜单ID列表
	                Object[] params = new Object[batch.size() + 1];
	                params[0] = id;
	                for (int j = 0; j < batch.size(); j++) {
	                    params[j + 1] = batch.get(j);
	                }
	                
	                // 修复SQL：使用参数化查询
	                String sql = "DELETE FROM " + RoleMenu.TABLE_NAME + 
	                             " WHERE role_id = ? AND menu_id IN (" + placeholders + ")";
	                
	                int deleteCount = Db.delete(sql, params);
	                log.debug("角色[{}]移除{}个菜单", id, deleteCount);
	            }
	            log.info("角色[{}]共移除{}个菜单", id, idsToDelete.size());
	        }

	        // 5. 批量新增操作 (避免逐条插入)
	        if (!idsToAdd.isEmpty()) {
	            // 分批次处理（每批最多1000个）
	            int batchSize = 1000;
	            for (int i = 0; i < idsToAdd.size(); i += batchSize) {
	                int end = Math.min(i + batchSize, idsToAdd.size());
	                List<String> batch = idsToAdd.subList(i, end);
	                
	                List<RoleMenu> newRoleMenus = batch.stream()
	                    .map(menuId -> {
	                        RoleMenu rm = new RoleMenu();
	                        rm.setRoleId(id);
	                        rm.setMenuId(menuId);
	                        return rm;
	                    })
	                    .collect(Collectors.toList());
	                
	                Db.batchSave(newRoleMenus, newRoleMenus.size());
	                log.debug("角色[{}]新增{}个菜单", id, newRoleMenus.size());
	            }
	            log.info("角色[{}]共新增{}个菜单", id, idsToAdd.size());
	        }
	        // 6. 返回成功响应
	        return R.ok("菜单授权更新成功");
	    } catch (Exception e) {
	        // 7. 改进异常处理和日志记录
	        log.error("保存角色[{}]菜单异常: {}", id, ExceptionUtils.getStackTrace(e));
	        return R.fail("菜单授权更新失败，请稍后重试");
	    }
	}
	
	
    @PostMapping("/options")
    @Operation(summary = "获取角色下拉框", description = "分页查询角色数据")
    public R<List<Role>> options(@RequestBody PageQuery<Role> pageQuery) {
        return R.ok(roleService.options(pageQuery));
    }
    
} 